/*-------------------------------------------------------------------------
 *
 * hashutils.c--
 *    Utilities for finding applicable merge clauses and pathkeys
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *    $Header: /usr/local/cvsroot/postgres95/src/backend/optimizer/path/hashutils.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"
#include "nodes/pg_list.h"
#include "nodes/relation.h"

#include "optimizer/internal.h"
#include "optimizer/paths.h"
#include "optimizer/clauses.h"


static HInfo *match_hashop_hashinfo(Oid hashop, List *hashinfo_list);

/*    
 * group-clauses-by-hashop--
 *    If a join clause node in 'clauseinfo-list' is hashjoinable, store
 *    it within a hashinfo node containing other clause nodes with the same
 *    hash operator.
 *    
 * 'clauseinfo-list' is the list of clauseinfo nodes
 * 'inner-relid' is the relid of the inner join relation
 *    
 * Returns the new list of hashinfo nodes.
 *    
 */
List *
group_clauses_by_hashop(List *clauseinfo_list,
			int inner_relid)
{
    List *hashinfo_list = NIL;
    CInfo *clauseinfo = (CInfo*)NULL;
    List *i = NIL;
    Oid hashjoinop = 0;
    
    foreach (i,clauseinfo_list) {
	clauseinfo = (CInfo*)lfirst(i);
	hashjoinop = clauseinfo->hashjoinoperator;
	
	/*
	 * Create a new hashinfo node and add it to 'hashinfo-list' if one
	 * does not yet exist for this hash operator.
	 */
	if (hashjoinop ) {
	    HInfo *xhashinfo = (HInfo*)NULL;
	    Expr *clause = clauseinfo->clause;
	    Var *leftop = get_leftop(clause);
	    Var *rightop = get_rightop(clause);
	    JoinKey *keys = (JoinKey*)NULL;
	    
	    xhashinfo = 
		match_hashop_hashinfo(hashjoinop,hashinfo_list);
	    
	    if (inner_relid == leftop->varno){
		keys = makeNode(JoinKey);
		keys->outer = rightop;
		keys->inner = leftop;
	    } else {
		keys = makeNode(JoinKey);
		keys->outer = leftop;
		keys->inner = rightop;
	    }
	    
	    if (xhashinfo==NULL) {
		xhashinfo = makeNode(HInfo);
		xhashinfo->hashop = hashjoinop;

		xhashinfo->jmethod.jmkeys = NIL;
		xhashinfo->jmethod.clauses = NIL;

		/* XXX was push  */
		hashinfo_list = lappend(hashinfo_list,xhashinfo);
		hashinfo_list = nreverse(hashinfo_list);
	    }

	    xhashinfo->jmethod.clauses =
		lcons(clause, xhashinfo->jmethod.clauses);

	    xhashinfo->jmethod.jmkeys =
		lcons(keys, xhashinfo->jmethod.jmkeys);
	}
    }
    return(hashinfo_list);
}


/*    
 * match-hashop-hashinfo--
 *    Searches the list 'hashinfo-list' for a hashinfo node whose hash op
 *    field equals 'hashop'.
 *    
 * Returns the node if it exists.
 *    
 */
static HInfo *
match_hashop_hashinfo(Oid hashop, List *hashinfo_list)
{
    Oid key = 0;
    HInfo *xhashinfo = (HInfo*)NULL;
    List *i = NIL;
    
    foreach( i, hashinfo_list) {
	xhashinfo = (HInfo*)lfirst(i);
	key = xhashinfo->hashop;
	if (hashop == key) {	/* found */
	    return(xhashinfo);	/* should be a hashinfo node ! */
	}
    }
    return((HInfo*)NIL);
}
